﻿========================================================================
  JPKI Web 署名システム  Version 0.2.0
========================================================================

  ソフト名     : JPKI Web 署名システム
  バージョン   : 0.2.0
  作 者        : highdefinitionaudiodriver
  動作環境     : Windows 10/11, macOS 12+, Linux / Python 3.10 以上
  ライセンス   : MIT License（フリーソフト／オープンソース）
  種 別        : フリーソフト
  作成日       : 2026-06-08

------------------------------------------------------------------------
■ ソフトの説明 / 使用方法（README より）
------------------------------------------------------------------------

🪪 JPKI Web

> マイナンバーカード（JPKI）で画像に電子署名を付与し、その真贋をブラウザから検証できるローカル運用ツール。

個人間（C2C）の合意・契約書の画像に対して、マイナンバーカード由来の電子署名で「誰が署名したか」と「画像が改ざんされていないか」を担保することを目的とした、信頼担保型の証明ツールです。

FastAPI（Python）+ Vanilla JS で構成されており、ユーザー自身のローカル PC で起動して、IC カードリーダーに刺したマイナンバーカードを直接操作します。

---

🎯 これは何？（30秒で）

- 想定読者（ターゲット層）：
  1. 行政書士・司法書士などの士業の方（顧客への真贋証明レポートの作成や、デジタル署名を活用した新しい法的サービスの提供）
  2. 個人間（C2C）契約の当事者の方（不動産の個人売買、機密保持合意、委任状などを安全にデジタル化したい個人）
  3. 自治体の実証実験・PoC担当者の方（JPKIを活用した住民投票や合意形成、電子申請のローカル運用シミュレーション）
- 何が解決される：紙の契約書をスキャンしただけでは「本人性」も「改ざん検知」も担保できない問題を、マイナンバーカード由来の公的個人認証署名で同時に解決
- なぜ既存ツールではダメか：商用電子契約サービスは月額課金＋クラウド保管が前提。本ツールは 完全ローカル運用・サーバー不要・PIN がネットワークに出ない 設計
- 使う条件：Windows / macOS / Linux、Python 3.12+、PC/SC 対応 IC カードリーダー、マイナンバーカード（署名用電子証明書が有効なもの）

💰 想定ユースケース・価格帯

| 用途 | 形態 |
|---|---|
| 個人利用（自分の契約・委任状・合意書への署名） | 無料（MIT） |
| 士業の業務利用（顧客向け真贋検証レポート発行） | 無料（MIT）／導入支援は応相談 |
| 自治体・企業の実証実験・PoC | 導入支援・カスタマイズ受託（応相談） |

---


---

🔴 重要：セキュリティ — ローカル運用専用

> このアプリは "あなた自身のローカルマシン (127.0.0.1)" で起動することを唯一の運用形態として設計されています。
> VPS / クラウド / 共有サーバー等にデプロイしては絶対にいけません。

理由：

- 署名処理時、JPKI の 署名用 PIN を HTTP リクエストで FastAPI に送信 します。
- ローカルバインド (127.0.0.1) であれば PIN は同一マシン内のループバック通信に閉じます。
- リモートサーバーにデプロイした場合、PIN がネットワークを越えて流れることになり、PIN の盗聴や、最悪の場合はカードのロック・なりすまし署名に直結します。
- IC カードリーダーは PC/SC（pyscard）でローカル接続のみを想定しており、リモート環境では物理的に動作しません。

本実装では下記の二重防衛を組み込んでいます：

| 項目 | 実装 |
|---|---|
| バインドアドレス | README で --host 127.0.0.1 必須を明記 |
| CORS 許可 | http://127.0.0.1:8000 / http://localhost:8000 のみ |
| PIN ライフタイム | 受信 → verify_pin 呼び出し → 即破棄。ログ・例外メッセージに絶対に含めない |
| カード側ロック防止 | 残回数 < 3 回で送信前中止（pin_risk） |
| サーバ側ソフトロック | プロセス内で 3 回失敗でサーバ再起動まで /api/sign 停止（soft_locked） |
| 同時実行 | asyncio.Lock で 1 件にシリアライズ（PC/SC 競合回避） |

---

🔴 重要：プライバシー — 生成ファイルの取り扱い

/api/sign で生成される .jpkiimg には、内部に JPKI 署名用電子証明書 が同梱されています。
この証明書には以下の 個人情報 が含まれます：

- 氏名（漢字）
- 住所（漢字）
- 生年月日
- 性別
- JPKI 識別符号（17桁の補助番号）

取り扱いの厳守事項：

- ❌ 公開リポジトリ（GitHub 等）への push 厳禁 — 本リポジトリは .gitignore で *.jpkiimg 等を除外済み
- ❌ SNS への投稿、公開チャット、フォーラム等への貼り付け厳禁
- ❌ 生 JSON のスクリーンショット公開厳禁（signer.subject_cn に識別符号が含まれます）
- ✅ 信頼できる相手への直接送付（個人間契約の証跡として）のみに限定

---

✨ 機能

| カテゴリ | エンドポイント | 概要 |
|---|---|---|
| 検証 | POST /api/verify | .jpkiimg をアップロードし、PKCS#7 分離署名を検証して署名者氏名・有効期間を返す |
| 署名 | POST /api/sign | 画像 (PNG/JPEG) と PIN を受け取り、JPKI カードで署名して .jpkiimg を返す |
| 本人認証 | POST /api/read-certificate | PINなしで利用者証明用電子証明書を読み取り、証明書シリアル等を返す |
| ヘルス | GET /api/health | サーバー稼働確認とソフトロック状況の取得 |
| UI | GET / | 検証 / 署名のタブ UI |

制限事項（現バージョン）

- 対応形式は .jpkiimg（独自 ZIP コンテナ）のみ。PDF（PAdES）対応は今後の課題
- 証明書チェーン検証 / 失効確認（CRL / OCSP）は未実装 — 改ざん検知は可能だが、有効性証明は別途必要
- タイムスタンプトークン（RFC 3161）未対応 — 「いつ署名したか」の第三者証明は別途必要
- リーダーは PC/SC 接続の物理 IC カードリーダーのみ（pyscard 経由）

---

🏗 アーキテクチャ


   ┌──────────────────────────────────────────┐
   │  ブラウザ (タブ UI)                       │
   │   ・ Verify : .jpkiimg をアップロード     │
   │   ・ Sign   : 画像 + PIN を入力           │
   └────────────┬─────────────────────────────┘
                │ HTTP (127.0.0.1:8000 のみ)
                ▼
   ┌──────────────────────────────────────────┐
   │  FastAPI (このプロセス、ローカルのみ)      │
   │   ┌─ /api/verify : 検証ロジック          │
   │   └─ /api/sign   : 同時1件にシリアライズ  │
   │        │                                 │
   │        │  PC/SC (pyscard)                │
   │        ▼                                 │
   │  ┌──────────────────┐                    │
   │  │ JpkiSession      │                    │
   │  │  - VERIFY PIN    │                    │
   │  │  - COMPUTE SIG   │                    │
   │  │  - READ CERT     │                    │
   │  └──────┬───────────┘                    │
   └─────────┼────────────────────────────────┘
             ▼
       🪪 マイナンバーカード (IC カードリーダー)


.jpkiimg コンテナ仕様


sample.jpg.jpkiimg  (無圧縮 ZIP)
├── target_image.jpg     ← 元画像 (無加工)
├── signature.p7s        ← PKCS#7 分離署名 (DER)
└── cert.der             ← JPKI 署名用電子証明書 (DER)


PKCS#7 は CMS SignedData（detached / 最小構成）として構築され、署名アルゴリズムは RSASSA-PKCS1-v1_5 + SHA-256、signedAttrs は付加しません（JPKI カードの COMPUTE DIGITAL SIGNATURE と直接対応）。

---

🛠 前提条件

共通

- Python 3.12 以降（3.14 系は pyscard が wheel 未対応のため非推奨。3.12 を強く推奨）
- 物理 IC カードリーダー（PC/SC 対応 / 接触式または NFC）
- マイナンバーカード（署名用電子証明書が有効であること）
- 必要に応じて JPKI 利用者クライアントソフト（J-LIS 配布）— PC/SC への登録に必要なことがあります
  - https://www.jpki.go.jp/download/

pyscard のシステム依存（OS 別）

pyscard は OS の PC/SC レイヤをラップする C 拡張を含みます。プリビルド wheel が無い環境ではビルドツールが必要になります。

Windows

- Smart Card サービス (SCardSvr): 標準で利用可能（Get-Service SCardSvr で確認）
- Python 3.12 用の wheel が PyPI にあるため、通常は追加ビルドツール不要で pip install できます
- ビルドが必要になった場合:
  - [Microsoft C++ Build Tools](https://visualstudio.microsoft.com/visual-cpp-build-tools/) の「C++ によるデスクトップ開発」ワークロード
  - [SWIG for Windows](https://www.swig.org/download.html)（zip 展開して PATH に追加）

macOS

- PC/SC は OS 標準で動作します
- 多くの場合 pip install がそのまま通りますが、ビルド時は以下が必要：
  
  brew install swig
  xcode-select --install   # Command Line Tools
  

Linux

- PC/SC デーモン: pcscd を起動しておく必要があります
  
  # Debian / Ubuntu
  sudo apt install pcscd libpcsclite-dev swig
  sudo systemctl enable --now pcscd

  # Fedora / RHEL
  sudo dnf install pcsc-lite pcsc-lite-devel swig
  sudo systemctl enable --now pcscd
  
- ユーザーをスマートカード関連グループに追加する必要がある場合があります（ディストリ依存）

リーダー認識の事前確認（推奨）

セットアップ前にリーダーが OS から見えているかを確認してください：


Windows
Get-Service SCardSvr           # Status が Running か
certutil -scinfo               # リーダー名と ATR が出るか



macOS / Linux
pcsc_scan                      # リーダーとカードを継続スキャン


---

🚀 セットアップ

1. リポジトリ取得


git clone <YOUR_REMOTE_URL>
cd jpki-web


2. 仮想環境 + 依存インストール


Windows (PowerShell)
py -3.12 -m venv .venv
.\.venv\Scripts\Activate.ps1
↑ ExecutionPolicy で弾かれる場合:
Set-ExecutionPolicy -Scope CurrentUser RemoteSigned
あるいは venv を使わず py -3.12 -m pip install -r requirements.txt でも可

py -3.12 -m pip install -r requirements.txt



macOS / Linux
python3.12 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt


依存・ローカル運用診断

起動前に FastAPI / 暗号 / PC/SC 依存、主要ファイル、ローカル運用のREADME記載、APIルート定義を確認できます。


py -3.12 tools\check_setup.py


3. 起動


Windows
py -3.12 -m uvicorn app.main:app --reload --reload-dir app --host 127.0.0.1 --port 8000



macOS / Linux
python -m uvicorn app.main:app --reload --reload-dir app --host 127.0.0.1 --port 8000


> ⚠️ 必ず --host 127.0.0.1 を付けてください。 0.0.0.0 での公開は PIN 漏洩のリスクのため厳禁です。

ブラウザで http://127.0.0.1:8000/ を開きます。

---

📖 使い方

検証 (Verify)

1. 「🔍 検証」タブを開く
2. .jpkiimg ファイルを選択
3. 「署名を検証する」 → 結果（署名者氏名、証明書有効期間 等）が表示

署名 (Sign)

1. 「✍️ 署名」タブを開く
2. IC カードリーダーをマイナンバーカードと共に PC に接続
3. 画像（PNG/JPEG）を選択し、署名用 PIN（6〜16 桁）を入力
4. 「署名して .jpkiimg を生成」 → 自動的に .jpkiimg がダウンロード

> ⚠️ PIN を 5 回連続で間違えるとマイナンバーカードがロックされ、市区町村窓口での初期化が必要になります。
> 本ツールはサーバ側でも 3 回失敗で停止するソフトガードを備えていますが、入力前に必ず PIN を確認してください。

---

📡 API リファレンス

POST /api/verify

| リクエスト | multipart/form-data |
|---|---|
| file | .jpkiimg ファイル（最大 50MB） |

レスポンス（成功例）:


{
  "status": "success",
  "verified": true,
  "signer": {
    "name": "山田 太郎",
    "name_source": "san_jpki_other_name",
    "subject_cn": "識別符号(JPKI)",
    "not_valid_before": "2025-01-01T00:00:00+00:00",
    "not_valid_after":  "2030-01-01T00:00:00+00:00"
  },
  "image": { "name": "target_image.jpg", "size": 123456 },
  "file":  { "name": "sample.jpkiimg", "size": 124000, "content_type": "application/zip" },
  "message": "署名は有効です。画像は署名生成時から1ビットも改変されていません。",
  "error_kind": null,
  "checked_at": "2026-05-10T12:34:56+09:00"
}


エラー時の error_kind: not_jpkiimg / missing_entry / tampered / structure

POST /api/sign

| リクエスト | multipart/form-data |
|---|---|
| file | 画像ファイル PNG / JPEG（最大 30MB） |
| pin  | 署名用 PIN（6〜16 桁 ASCII） |

成功時:

- 200 OK
- Content-Type: application/octet-stream
- Content-Disposition: attachment; filename="<元ファイル名>.jpkiimg"
- ボディ = .jpkiimg バイナリ
- カスタムヘッダ: X-JPKI-Container-Size, X-JPKI-Reader

失敗時（JSON）:


{
  "status": "error",
  "error_kind": "pin_failed",
  "message": "PINが正しくありません。残り 4 回でロックされます。",
  "detail": { "remaining": 4 },
  "checked_at": "2026-05-10T12:34:56+09:00"
}


主な error_kind:

| kind | HTTP | 説明 |
|---|---|---|
| pin_failed | 401 | PIN 不一致（残回数を detail.remaining に格納） |
| pin_locked | 423 | カード側ロック（窓口での初期化が必要） |
| pin_risk | 409 | 残回数 < 3。安全装置で送信中止 |
| soft_locked | 423 | サーバ側ソフトロック（再起動が必要） |
| no_reader | 503 | IC カードリーダー未検出 |
| card_error | 502 | カード通信失敗（detail.sw に SW を格納） |
| busy | 409 | 他の署名処理が進行中 |
| unsupported_extension / too_large / empty_image | 415 / 413 / 400 | 入力検証 |

---

📁 ディレクトリ構成


jpki-web/
├── app/
│   ├── main.py                 # FastAPI エントリポイント
│   ├── jpki_signer/            # 署名・検証ロジック
│   │   ├── service.py          # 高レベルサービス
│   │   ├── jpki/               # PC/SC + APDU + JPKI セッション
│   │   ├── crypto/             # PKCS#7 構築・検証 / 証明書抽出
│   │   └── container/          # .jpkiimg ZIP R/W
│   ├── uploads/                # アップロード保管 (gitignore対象)
│   └── static/                 # フロントエンド (Vanilla JS)
│       ├── index.html
│       ├── app.js
│       └── styles.css
├── requirements.txt
├── README.md
├── LICENSE
└── .gitignore


---

🗺 ロードマップ

- [ ] PDF (PAdES) 形式への対応
- [ ] 証明書チェーン検証 / 失効確認 (CRL / OCSP)
- [ ] タイムスタンプトークン (RFC 3161) の付与
- [ ] 利用者証明用証明書 (auth) を使った認証用途
- [ ] Electron 等でのスタンドアロン配布
- [ ] 複数リーダー検出時の選択 UI
- [ ] pytest による自動テスト + GitHub Actions CI

---

🤝 Contributing

イシュー・PR 歓迎です。ただし以下の点にご留意ください：

- 個人情報を含む .jpkiimg / 証明書を絶対にコミット・添付しないでください。
- セキュリティに関わる変更（PIN 取り扱い、CORS、ローカル運用前提）は事前にイシューで議論をお願いします。

---

📜 ライセンス

MIT License — 詳細は [LICENSE](LICENSE) を参照してください。

検証・署名ロジック（app/jpki_signer/ 配下）は別プロジェクト（[jpki-image-signer]、未公開）由来のコードを内蔵しています。

---

⚠️ 免責事項

本ツールはプロトタイプです。法的効力のある電子署名としての利用については、各種法令（電子署名法等）や運用ガイドラインを別途確認した上で、利用者の責任にてご使用ください。

本ツールの使用により生じたいかなる損害についても、作者は一切の責任を負いません。

---

🤝 商用利用・カスタマイズ依頼

- 個人利用は無料（MIT ライセンス）
- 企業・自治体導入支援、カスタマイズ、士業向け検証レポート様式の調整、PoC 受託は応相談
- 連絡先：highdefinitionaudiodriver@gmail.com

<!-- CODEX-CURRENT-STATUS:START -->
現状サマリ (2026-05-25)

- 対象: 🪪 JPKI Web
- 作業ブランチ: main
- README更新時点の参照コミット: 2026-05-27 Codex作業時点
- Python 実行環境向けに requirements.txt を同梱。
- docs ディレクトリ配下に設計・運用・補足資料を配置。
- 主要な確認コマンド: python tools/check_setup.py / python -m unittest discover -s tests
- 次に進めるなら、実カード・ICカードリーダーで /api/read-certificate の結合確認、UIデモボタン追加、CI向けの依存なしテスト拡充を行う。
<!-- CODEX-CURRENT-STATUS:END -->

------------------------------------------------------------------------
■ 動作環境
------------------------------------------------------------------------
  Windows 10/11, macOS 12+, Linux / Python 3.10 以上
  ※ オンライン専用ソフトではありません（ローカル環境で動作します）。

------------------------------------------------------------------------
■ インストール / アンインストール
------------------------------------------------------------------------
  ・本アーカイブを任意のフォルダに展開してください。
  ・詳細な起動手順は上記「ソフトの説明」および同梱の README を参照してください。
  ・アンインストールは展開したフォルダを削除するだけです（レジストリ不使用）。

------------------------------------------------------------------------
■ 転載・再配布について
------------------------------------------------------------------------
  本ソフトは MIT License のオープンソースです。同梱の LICENSE 条文に
  従う限り、自由に利用・改変・再配布できます。
  なお Vector 以外の配布サイトへの無断転載はご遠慮ください。

------------------------------------------------------------------------
■ 免責事項
------------------------------------------------------------------------
  本ソフトの使用によって生じたいかなる損害についても、作者は一切の
  責任を負いません。利用者ご自身の責任においてご使用ください。

------------------------------------------------------------------------
■ 著作権
------------------------------------------------------------------------
  Copyright (c) 2026 highdefinitionaudiodriver
  本ソフトは MIT License の下で公開されています。

------------------------------------------------------------------------
■ 連絡先 / サポート
------------------------------------------------------------------------
  作 者        : highdefinitionaudiodriver
  E-mail       : highdefinitionaudiodriver@gmail.com
  GitHub       : https://github.com/highdefinitionaudiodriver/jpki-web.git
  不具合報告・ご要望は上記 E-mail もしくはリポジトリの Issues へ
  お願いいたします。

========================================================================
